package com.matt.service.impl;

import com.aliyun.oss.OSSClient;
import com.matt.commons.dto.sso.StaffDTO;
import com.matt.commons.exception.BusinessException;
import com.matt.domain.Children;
import com.matt.foundation.ext.aliyun.OSSProcessService;
import com.matt.foundation.utils.DateUtil;
import com.matt.repository.ChildrenRepository;
import com.matt.service.UploadService;
import com.matt.service.remoteCall.SsoCallService;
import com.matt.utils.ConstantPropertiesUtil;
import com.tuo51.evaluate.service.EvaluateV2ExportService;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.imageio.ImageIO;
import javax.transaction.Transactional;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.text.SimpleDateFormat;
import java.util.*;

import static com.matt.foundation.model.ErrorCode.CHILDREN_NOT_EXIST;
import static com.matt.foundation.model.ErrorCode.STAFF_NOT_EXIST;

/**
 * *******************************
 * Created by Ron.
 * form com.matt
 * on 2017/7/26
 * *******************************
 */
@Service
@Transactional
public class UploadServiceImpl implements UploadService {

    @Autowired
    private ChildrenRepository childrenRepository;

    @Autowired
    private OSSProcessService fileProcessService;

    @Autowired
    private SsoCallService ssoCallService;

    @Value("${aliyun.oss.filePathPrefix}")
    private String filePathPrefix;

    @Value("${aliyun.oss.fileServerPrefix}")
    private String IMG_SERVICE_PREFIX;

    @Override
    public Children uploadChildrenHeadImg(String childrenId, MultipartFile file) {
        String originalName = file.getOriginalFilename();
        String extension = originalName.substring(originalName.lastIndexOf("."));
        Children children = childrenRepository.getOne(childrenId);
        if (Objects.isNull(children))
            throw new BusinessException(CHILDREN_NOT_EXIST, "宝宝不存在");
        String fileName = children.getId() + "/" + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM-dd_HH-mm-ss-SSS") + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + "children/" + fileName, file);
        children.setImgUrl(IMG_SERVICE_PREFIX + relativePath);
        childrenRepository.save(children);
        return children;
    }

    @Override
    public String uploadTeacherHeadImg(String ticket, MultipartFile file) {
        String extension = getExtension(file);
        StaffDTO staff = ssoCallService.getStaffDTO(ticket);
        if (Objects.isNull(staff))
            throw new BusinessException(STAFF_NOT_EXIST, "老师不存在");
        String fileName = staff.getId() + "/" + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM-dd_HH-mm-ss-SSS") + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + "teacher/" + fileName, file);
        String url = IMG_SERVICE_PREFIX + relativePath;

        staff.setHeadImgUrl(url);
        ssoCallService.updateStaff(ticket, staff);

        return url;
    }

    private static String getExtension(MultipartFile file) {
        String originalName = file.getOriginalFilename();
        String extension = originalName.substring(originalName.lastIndexOf("."));
        return extension;
    }


    @Override
    public String uploadLiveRecordImg(String staffId, Integer type, MultipartFile[] files) {
        return uploadMultiPartFiles(type, "live_record", staffId, files);
    }

    @Override
    public String uploadCourseLiveRecordImg(String staffId, Integer type, MultipartFile[] files) {
        return uploadMultiPartFiles(type, "course_live_record", staffId, files);
    }

    @Override
    public String uploadBirthdayRecordImg(String staffId, Integer type, MultipartFile[] files) {
        return uploadMultiPartFiles(type, "birthday_record", staffId, files);
    }

    @Override
    public String uploadCheckInRecordImg(String childrenId, MultipartFile file) {
        String extension = getExtension(file);
        String fileName = childrenId + "/" + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM-dd_HH-mm-ss-SSS") + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + "check_record/checkIn_" + fileName, file);
        return IMG_SERVICE_PREFIX + relativePath;
    }

    @Override
    public String uploadCheckOutRecordImg(String childrenId, MultipartFile file) {
        String extension = getExtension(file);
        String fileName = childrenId + "/" + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM-dd_HH-mm-ss-SSS") + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + "check_record/checkOut_" + fileName, file);
        return IMG_SERVICE_PREFIX + relativePath;
    }


    @Override
    public String uploadCourseAreaAttachment(MultipartFile file) {
        return uploadCourseFile("course_area_", "course/courseArea/", file);
    }

    @Override
    public String uploadCourseOfficialAttachment(MultipartFile file) {
        return uploadCourseFile("course_official_", "course/courseOfficial/", file);
    }

    @Override
    public String uploadCourseTopicAdvise(MultipartFile file) {
        return uploadCourseFile("course_topic_", "course/courseTopic/", file);
    }

    @Override
    public String uploadObservationRecordImg(Integer type, MultipartFile[] files) {
        return uploadMultiPartFiles(type, "observation_record", null, files);
    }

    @Override
    public String uploadPrepareToolImg(MultipartFile file) {
        return uploadCourseFile("", "prepareTool/", file);
    }



    public String uploadCourseFile(String fileNamePrefix, String secondPath, MultipartFile file) {
        String extension = getExtension(file);
        String fileName = fileNamePrefix + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM-dd_HH-mm-ss-SSS") + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + secondPath + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM") + "/" + fileName, file);
        return IMG_SERVICE_PREFIX + relativePath;
    }





    public String uploadMultiPartFiles(Integer type, String secondPath, String staffId, MultipartFile[] files) {

        if (files == null){
            return null;
        }

        String fileName = "";
        if (2 == type) {
            String originalName = files[0].getOriginalFilename();
            String extension = originalName.substring(originalName.lastIndexOf("."));
            fileName += DateUtil.millisToDateTime(System.currentTimeMillis(), "_yyyy-MM-dd_HH-mm-ss-SSS") + extension;
            String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + secondPath + "/video/" + fileName, files[0]);
            return IMG_SERVICE_PREFIX + relativePath;
        } else if (1 == type) {
            String filePath = "";
            for (MultipartFile file : files) {
                fileName = "";
                String originalName = file.getOriginalFilename();
                String extension = originalName.substring(originalName.lastIndexOf("."));
                fileName += DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM-dd_HH-mm-ss-SSS") + extension;
                String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + secondPath + "/img/" + fileName, file);
                filePath += IMG_SERVICE_PREFIX + relativePath + "|";
            }
            return StringUtils.substring(filePath, 0, filePath.length() - 1);
        }
        return null;
    }

    @Override
    public String uploadLiveRoomImg(String yingShiId, MultipartFile file) {
        String extension = getExtension(file);
        String fileName = yingShiId + "_"+ System.currentTimeMillis() + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + "live_room/" + fileName, file);
        return IMG_SERVICE_PREFIX + relativePath;
    }

    @Override
    public String uploadSimpleCookbookImg(String staffId, MultipartFile file){
        String extension = getExtension(file);
        String fileName = staffId + "_"+ System.currentTimeMillis() + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + "simple_cookbook/" + fileName, file);
        return IMG_SERVICE_PREFIX + relativePath;
    }

    @Override
    public String uploadPhoto(String staffId, String albumId, MultipartFile file){
        String extension = getExtension(file);
        String fileName = staffId + "_"+ System.currentTimeMillis() + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + "photo/" + albumId + "/" + fileName, file);
        return IMG_SERVICE_PREFIX + relativePath;
    }

    @Override
    public String uploadFile(MultipartFile file) {
        return uploadCourseFile("", "system/", file);
    }

    private String uploadFile(String fileName, MultipartFile file) {
        String relativePath = fileProcessService.aliyunOssUpload(fileName, file);
        return IMG_SERVICE_PREFIX + relativePath;
    }

    @Override
    public String uploadCommonFile(String staffId, String type, MultipartFile file){
        String extension = getExtension(file);
        String fileName = staffId + "_"+ System.currentTimeMillis() + extension;
        String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + "common/" + type + "/" + fileName, file);
        return IMG_SERVICE_PREFIX + relativePath;
    }

    @Override
    public String uploadComplaintRecordImg(String usersId, MultipartFile[] files) {
        return uploadMultiPartFiles(1, "complaint_record", usersId, files);
    }

    @Override
    public String uploadStaticPhotoAlbum(String filePath) throws IOException {
        return uploadLocalFile(filePath, "photoalbum");
    }

    @Override
    public String uploadStaticEvaluateReport(String childrenName, String filePath) throws IOException {
        return uploadLocalFile(filePath, "evaluate_report", childrenName);
    }

    @Override
    public String uploadStaticPBEvaluateReport(String childrenName, String filePath) throws IOException{
        return uploadLocalFile(filePath, "pb_evaluate_report", childrenName);
    }

    @Override
    public String uploadLocalFile(String url, String type) throws IOException{
        return uploadLocalFile(url, type, "");
    }

    @Override
    public String uploadLocalFile(String localFileURL, EvaluateV2ExportService.ExportType type, String prefix){
        try {
            return uploadLocalFileE(localFileURL, type, prefix);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String uploadLocalFile(File file, EvaluateV2ExportService.ExportType type, String fileNamePrefix) {
        FileItem fileItem = null;
        try {
            System.out.println("Files.probeContentType(file.toPath()) Files.probeContentType(file.toPath()) is "+Files.probeContentType(file.toPath()));
            fileItem = new DiskFileItem("mainFile", Files.probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile());
        } catch (IOException e) {
            e.printStackTrace();
        }

        String uploadedResult = null;
        //写文件
        try {
            InputStream input = new FileInputStream(file);
            OutputStream os = fileItem.getOutputStream();
            IOUtils.copy(input, os);
            // Or faster..
            // IOUtils.copy(new FileInputStream(file), fileItem.getOutputStream());

            MultipartFile multipartFile = new CommonsMultipartFile(fileItem);

//            String fileName = fileNamePrefix + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM-dd_HH-mm-ss-SSS") + extension;
//            String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + secondPath + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM") + "/" + fileName, file);
//            https://e.res.tuo51.com/51evaluation/file/evaluate_report/2020-08/%E7%8E%8B%E7%BB%98%E7%84%B6_%E5%BF%83%E7%90%86%E8%A1%8C%E4%B8%BA%E8%AF%84%E6%B5%8B%E6%8A%A5%E5%91%8A_2020-08-15_10-34-29-322.doc
//            filePathPrefix: 51evaluation_dev/file/

            String fileName = filePathPrefix + type.getFolderName() + "/" + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM") + "/";
            String timestamp = DateUtil.millisToDateTime(System.currentTimeMillis(), "dd_HH-mm-ss-SSS");
            fileName += String.format(type.getFileName(), fileNamePrefix, timestamp);

            System.out.println("fileName fileName fileName is "+fileName+"   type.getFileName() is  "+type.getFileName());

            uploadedResult = uploadFile(fileName, multipartFile);

        } catch (IOException ex) {
            // do something.
            ex.printStackTrace();
        } finally {
            if(file.exists()){
                file.delete();
            }
        }

        return uploadedResult;
    }

    private String uploadLocalFileE(String localFileURL, EvaluateV2ExportService.ExportType type, String fileNamePrefix) throws IOException {
        File file = new File(localFileURL);
        FileItem fileItem = new DiskFileItem("mainFile", Files.probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile());

        String uploadedResult = null;
        //写文件
        try {
            InputStream input = new FileInputStream(file);
            OutputStream os = fileItem.getOutputStream();
            IOUtils.copy(input, os);
            // Or faster..
            // IOUtils.copy(new FileInputStream(file), fileItem.getOutputStream());

            MultipartFile multipartFile = new CommonsMultipartFile(fileItem);

//            String fileName = fileNamePrefix + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM-dd_HH-mm-ss-SSS") + extension;
//            String relativePath = fileProcessService.aliyunOssUpload(filePathPrefix + secondPath + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM") + "/" + fileName, file);
//            https://e.res.tuo51.com/51evaluation/file/evaluate_report/2020-08/%E7%8E%8B%E7%BB%98%E7%84%B6_%E5%BF%83%E7%90%86%E8%A1%8C%E4%B8%BA%E8%AF%84%E6%B5%8B%E6%8A%A5%E5%91%8A_2020-08-15_10-34-29-322.doc
//            filePathPrefix: 51evaluation_dev/file/

            String fileName = filePathPrefix + type.getFolderName() + "/" + DateUtil.millisToDateTime(System.currentTimeMillis(), "yyyy-MM") + "/";
            String timestamp = DateUtil.millisToDateTime(System.currentTimeMillis(), "dd_HH-mm-ss-SSS");
            fileName += String.format(type.getFileName(), fileNamePrefix, timestamp);

            uploadedResult = uploadFile(fileName, multipartFile);

        } catch (IOException ex) {
            // do something.
            ex.printStackTrace();
        } finally {
            if(file.exists()){
                file.delete();
            }
        }

        return uploadedResult;
    }

    public String uploadLocalFile(String url, String type, String prefix) throws IOException {
        File file = new File(url);
        FileItem fileItem = new DiskFileItem("mainFile", Files.probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile());

        String uploadedResult = null;
        //写文件
        try {
            InputStream input = new FileInputStream(file);
            OutputStream os = fileItem.getOutputStream();
            IOUtils.copy(input, os);
            // Or faster..
            // IOUtils.copy(new FileInputStream(file), fileItem.getOutputStream());
            //上传oss
            MultipartFile multipartFile = new CommonsMultipartFile(fileItem);

            if (type.equals("photoalbum")) {
                uploadedResult = uploadCourseFile("starfish", "photo_album/", multipartFile);
            }else if(type.equals("evaluate_report") || type.equals("pb_evaluate_report")){
                uploadedResult = uploadCourseFile(prefix + "_", "evaluate_report/", multipartFile);
            }else{
                uploadedResult = uploadCourseFile(prefix + "_", type + "/", multipartFile);
            }
        } catch (IOException ex) {
            // do something.
            ex.printStackTrace();
        } finally {
            if(file.exists()){
                file.delete();
            }
        }

        return uploadedResult;
    }

    // 白名单（文件类型 + 扩展名）
    private static final List<String> ALLOWED_MIME_TYPES = new ArrayList<>();
    private static final List<String> ALLOWED_EXTENSIONS = new ArrayList<>();

    static {
        // 初始化允许的MIME类型和扩展名
        ALLOWED_MIME_TYPES.add("image/jpeg");
        ALLOWED_MIME_TYPES.add("image/png");
        ALLOWED_MIME_TYPES.add("application/pdf");

        ALLOWED_EXTENSIONS.add("jpg");
        ALLOWED_EXTENSIONS.add("jpeg");
        ALLOWED_EXTENSIONS.add("png");
        ALLOWED_EXTENSIONS.add("pdf");
    }
    public String uploadFileOss(MultipartFile file) throws IOException {
        String endpoint = ConstantPropertiesUtil.END_POINT;
        String accessKeyId = ConstantPropertiesUtil.ACCESS_KEY_ID;
        String accessKeySecret = ConstantPropertiesUtil.ACCESS_KEY_SECRET;
        String bucketName = ConstantPropertiesUtil.BUCKET_NAME;
        String bucketPath = ConstantPropertiesUtil.BUCKET_PATH;

            // 2. 检查文件类型和扩展名（双重校验）
        String originalFilename = file.getOriginalFilename();
        String fileExtension = getFileExtension(originalFilename).toLowerCase();
        String mimeType = file.getContentType();

        if (!ALLOWED_EXTENSIONS.contains(fileExtension) || !ALLOWED_MIME_TYPES.contains(mimeType)) {
            throw new IllegalArgumentException("禁止上传此文件类型");
        }

        // 3. 验证文件内容（以图片为例）
        if (isImageType(mimeType)) {
            BufferedImage image = ImageIO.read(file.getInputStream());
         if (image == null) {
                 throw new IllegalArgumentException("文件内容无效（非合法图片）");
             }
         }

         // 4. 生成安全文件名（随机UUID + 时间路径）
         String safeFilename = generateSafeFilename(originalFilename);

         // 5. 上传到OSS
         OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
         InputStream inputStream = file.getInputStream();

         try {
             ossClient.putObject(bucketName, safeFilename, inputStream);
          } finally {
              ossClient.shutdown();
          }

          // 6. 返回文件URL
          String url = "https://" + bucketPath + "/" + safeFilename;
          System.out.println("文件上传成功: " + url);
          return url;

        }

    // 获取文件扩展名
    private String getFileExtension(String filename) {
        if (filename == null || filename.isEmpty()) {
            return "";
        }
        int lastDotIndex = filename.lastIndexOf('.');
        return (lastDotIndex == -1) ? "" : filename.substring(lastDotIndex + 1);
    }

    // 生成安全文件名（UUID + 时间路径 + 去除特殊字符）
    private String generateSafeFilename(String originalFilename) {
        String fileExtension = getFileExtension(originalFilename);
        String baseName = originalFilename.replace("." + fileExtension, "");

        // 移除文件名中的特殊字符（仅保留字母、数字、下划线）
        baseName = baseName.replaceAll("[^a-zA-Z0-9_]", "");

        // 生成UUID + 时间路径 + 文件扩展名
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String timePath = new SimpleDateFormat("yyyy/MM/dd").format(new Date());
        return timePath + "/" + uuid + "." + fileExtension;
    }

    // 判断是否为图片类型
    private boolean isImageType(String mimeType) {
        return mimeType != null && mimeType.startsWith("image/");
    }
}
